﻿using Devil;
using GameToolkit.BehaviourTree;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

namespace GameToolkit.Editor
{

    public class BehaviourTreeSearchProvidor : ScriptableObject, ISearchWindowProvider
    {
        [SerializeField]
        bool m_IsDecoratorTree;

        bool mIsDirty = true;
        FilterDelegate<SearchTreeEntry> mFilter;
        BehaviourTreeGraph mGraph;

        public bool AsDecoratorTree
        {
            get { return m_IsDecoratorTree; }
            set
            {
                if(m_IsDecoratorTree != value)
                {
                    mIsDirty = true;
                    m_IsDecoratorTree = value;
                }
            }
        }

        public BehaviourTreeGraph Graph
        {
            get { return mGraph; }
            set
            {
                if (mGraph != value)
                {
                    mIsDirty = true;
                    if (mGraph != null)
                        mGraph.OnRegisterDirty -= OnGraphRegisterDirty;
                    mGraph = value;
                    if (mGraph != null)
                        mGraph.OnRegisterDirty += OnGraphRegisterDirty;
                }
            }
        }

        public FilterDelegate<SearchTreeEntry> Filter
        {
            get { return mFilter; }
            set
            {
                if (mFilter != value)
                {
                    mIsDirty = true;
                    mFilter = value;
                }
            }
        }

        public SelectSearchEntryCallback<BehaviourTreeSearchProvidor> OnSelectEntryAction { get; set; }

        List<SearchTreeEntry> mTemporaryLst = new List<SearchTreeEntry>();
        List<SearchTreeEntry> mRegisters = new List<SearchTreeEntry>();

        private void OnGraphRegisterDirty(BehaviourTreeGraph graph)
        {
            mIsDirty |= !m_IsDecoratorTree;
        }

        void UpdateRegisterNames()
        {
            var lib = BehaviourTreeLib.Instance;
            for (int i = 0; i < mRegisters.Count; i++)
            {
                var ent = mRegisters[i];
                ent.content.text = lib.GetDescription(((RegisterNodeVisual)ent.userData).composite);
            }
        }

        void GetRegisters(IList<SearchTreeEntry> lst)
        {
            mRegisters.Clear();
            if (mGraph != null && !m_IsDecoratorTree)
            {
                var lib = BehaviourTreeLib.Instance;
                var info = lib.GetCompositeInfo(typeof(RegisterReference));
                foreach (var node in mGraph.nodes)
                {
                    if (node is RegisterNodeVisual cnode && cnode.composite is RegisterComposite register)
                    {
                        var cat = lib.GetCategory(BehaviourTreeLib.EBTNodeType.Register);
                        var it = SearchTreeProviderUtils.AppendToSearchTreeList(cnode, $"{cat}/{lib.GetDescription(register)}", lst);
                        if (it != null)
                        {
                            if (info != null)
                                it.content.image = info.Icon;
                            mRegisters.Add(it);
                        }
                    }
                }
            }
        }

        public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
        {
            if (!mIsDirty)
            {
                UpdateRegisterNames();
                return mTemporaryLst;
            }
            mIsDirty = false;
            mTemporaryLst.Clear();
            mRegisters.Clear();
            if (m_IsDecoratorTree)
                mTemporaryLst.AddRange(BehaviourTreeLib.Instance.DecoratorSearchTree);
            else
                mTemporaryLst.AddRange(BehaviourTreeLib.Instance.ControllerAndBehaviuorSearchTree);
            GetRegisters(mTemporaryLst);
            if (mFilter != null)
            {
                int maxLv = 1;
                for (int i = mTemporaryLst.Count - 1; i >= 0; i--)
                {
                    var item = mTemporaryLst[i];
                    if (item is SearchTreeGroupEntry)
                        continue;
                    if (!Filter(item))
                    {
                        mTemporaryLst.RemoveAt(i);
                    }
                    else if (item.level > maxLv)
                    {
                        maxLv = item.level;
                    }
                }
                // clean empty groups
                var nums = new int[maxLv];
                for (int i = mTemporaryLst.Count - 1; i > 0; i--)
                {
                    var item = mTemporaryLst[i];
                    if (item is SearchTreeGroupEntry)
                    {
                        if (nums[item.level - 1] == 0)
                        {
                            mTemporaryLst.RemoveAt(i);
                        }
                        if (item.level == 1)
                        {
                            for (int k = 0; k < nums.Length; k++)
                            {
                                nums[k] = 0;
                            }
                        }
                    }
                    else
                    {
                        for (int k = 0; k < item.level; k++)
                        {
                            nums[k]++;
                        }
                    }
                }
            }
            return mTemporaryLst;
        }

        public bool OnSelectEntry(SearchTreeEntry entry, SearchWindowContext context)
        {
            bool result = false;
            if (OnSelectEntryAction != null && OnSelectEntryAction(this, entry, context))
                result = true;
            else if (Graph != null)
                result = Graph.OnSelectEntry(entry, context, m_IsDecoratorTree);
            else
                result = false;
            return result;
        }

        //internal static SearchTreeEntry AppendToSearchTreeList(object userData, string title, IList<SearchTreeEntry> searchLst)
        //{
        //    int startLv = 1;
        //    int startIndex = 1;
        //    var path = title.Split('/');
        //    SearchTreeEntry et;
        //    for (int i = 1; i < searchLst.Count; i++)
        //    {
        //        et = searchLst[i];
        //        if (et.level == startLv && et.name == path[startLv - 1])
        //        {
        //            startLv++;
        //            startIndex = i + 1;
        //        }
        //        else if(et.level < startLv)
        //        {
        //            break;
        //        }
        //    }
        //    var gsize = path.Length - 1;
        //    for (int i = startLv - 1; i < gsize; i++)
        //    {
        //        var grp = new SearchTreeGroupEntry(new GUIContent(path[i]), i + 1);
        //        if (startIndex < searchLst.Count)
        //        {
        //            searchLst.Insert(startIndex, grp);
        //            startIndex++;
        //        }
        //        else
        //        {
        //            searchLst.Add(grp);
        //            startIndex = searchLst.Count;
        //        }
        //    }
        //    et = new SearchTreeEntry(new GUIContent(path[gsize])) { level = path.Length };
        //    et.userData = userData;
        //    if (startIndex < searchLst.Count)
        //        searchLst.Insert(startIndex, et);
        //    else
        //        searchLst.Add(et);
        //    return et;
        //}
    }
}
